﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.DirectX.DirectDraw;
using DimsMapper.UIClasses;
using DimsMapper.Modules;
using KeyInput = System.Windows.Input;

namespace DimsMapper
{
    public partial class UserTab : UserControl
    {
        private Clipper mapClipper;
        private Surface mapSuface;
        private MapTab  map;

        private static bool scrollMapMode = false;
        private static int scrollDownMouseX;
        private static int scrollDownMouseY;
        private static int downHexX;
        private static int downHexY;
        private static int downTileX;
        private static int downTileY;

        private bool minimapOnce = false;
        private bool minimapHide = false;

        //private Object.GameObject inventorySelectedItem = null;
        private int inventorySelectedIndex = -1;
        private bool InventoryItemIsSelected = false;

        // выбранный предмет контенер в инвентаре объекта (движком допускается до 9 вложений)
        private int inventoryStackPos = -1;
        private Object.GameObject[] inventoryObjectStack = new Object.GameObject[9];

        private Object.Types navigatorObjectTypeTab = Object.Types.Tiles;
        private int[] navigatorPostion = { 1, 1, 1, 1, 1, 1, 1 };
        private int navigatorSelectedSlot = -1;
        private int[] navigatorSlotPids;
        private bool navigatorHasSelect;

        // Set the value of the double-buffering style bits to true.
        //void EnableDoubleBuffering()
        //{
        //   this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
        //   this.UpdateStyles();
        //}

        public UserTab(MapTab map)
        {
            InitializeComponent();

            this.map = map;
            mapClipper = MapDraw.CreatePrimarySurface(panelMap);

            labelElevations.Text += map.editedMap.Levels.ToString();
            numericElevation.Maximum = map.editedMap.Levels;

            PrintTotalObjects();

            map.MapRedraw += RefreshMap;
            panelNavigator.MouseWheel += PanelNavigator_MouseWheel;
            panelInventory.MouseWheel += PanelInventory_MouseWheel;
        }

        public void KeyPressEvent(KeyEventArgs e, bool isDown)
        {
            switch (e.KeyCode)
            {
                case Keys.ShiftKey:
                    panelMap.Cursor = (isDown) ? Cursors.SizeAll : Cursors.Cross;
                    map.moveObjectMode = isDown;
                    break;

                case Keys.Delete:
                    if (!isDown && map.mouseOverMap && map.editedMap.Objects.SelectedCount() > 0) {
                        if (e.Control || MessageBox.Show("Удалить объект(ы) с карты?", Application.ProductName, MessageBoxButtons.YesNo) == DialogResult.Yes) {
                            if (map.editedMap.Objects.DeleteSelectedObjects()) {
                                panelInventory.Visible = false;
                                RotationControl();
                                PrintTotalObjects();
                                RefreshMap();

                                map.MapChangeState(true);
                            }
                        }
                    }
                    break;
               case Keys.Oemcomma:
                    if (isDown && numObjectRotation.Enabled) {
                        numObjectRotation.Value -= 1;
                    }
                    break;
                case Keys.OemPeriod:
                    if (isDown && numObjectRotation.Enabled) {
                        numObjectRotation.Value += 1;
                    }
                    break;
            }
        }

        private void UserTab_Resize(System.Object sender, EventArgs e)
        {
            if (panelNavigator.Width <= 0 || panelMap.Width <= 0 || panelMap.Height <= 0) return;

            MapTab.cMapViewPortW = panelMap.Width;
            MapTab.cMapViewPortH = panelMap.Height;

            InventoryScrollSetup(0);             // установка скролла
            int count = NavigatorScrollSetup();  // установка скролла навигатора
            navigatorSlotPids = new int[count];

            if (mapSuface == null || panelMap.Width != mapSuface.SurfaceDescription.Width || panelMap.Height != mapSuface.SurfaceDescription.Height) {
                if (mapSuface != null) mapSuface.Dispose();
                mapSuface = MapDraw.CreateSurface(panelMap.Width, panelMap.Height);
            }
            MapDraw.DrawMap(map, mapSuface);
        }

        private void UserTab_VisibleChanged(System.Object sender, EventArgs e)
        {
        }

        private void PrintTotalObjects()
        {
            tssLabelTotalObjects.Text = "Objects: " + map.editedMap.Objects.TotalObjects().ToString();
        }

        #region Paint

        private void RefreshMap()
        {
            MapDraw.DrawMap(map, mapSuface);
            MapDraw.RepaintDDraw(panelMap, mapSuface, mapClipper);
        }

        private void RefreshMapTile(int tileX, int tileY)
        {
            MapDraw.DrawMap(map, mapSuface);
            MapDraw.DrawTilePoligon(tileX, tileY, map, mapSuface);
            MapDraw.RepaintDDraw(panelMap, mapSuface, mapClipper);
        }

        private void panelMap_Paint(System.Object sender, PaintEventArgs e)
        {
            MapDraw.RepaintDDraw(panelMap, mapSuface, mapClipper);
        }

        private void panelMinimap_Paint(System.Object sender, PaintEventArgs e)
        {
            if (!minimapOnce) {
                minimapOnce = true;
                MapDraw.DrawMinimap(map);
            }
            e.Graphics.Clear(Color.Black);
            if (minimapHide) return;

            e.Graphics.DrawImage(map.MiniMap.GetLevel(map.currentLevel - 1), 25 - (-100), 35, -100, 100); // отображаем зеркально по горизонтали
            e.Graphics.DrawRectangle(new Pen(Color.DarkRed), new Rectangle(25, 35, 100, 100));

            e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Low;
            e.Graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighSpeed;
            //e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;

            int x, y;
            Utilites.GetCursorTile(0, 0, map.cWorldX, map.cWorldY, out x, out y);
            x = 89 - x;
            e.Graphics.DrawImageUnscaled(Properties.Resources.locator, x + 30, y + 48);
        }

        private void panelNavigator_Paint(System.Object sender, PaintEventArgs e)
        {
            e.Graphics.Clear(Color.FromArgb(20, 20, 24));

            //e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Bilinear;
            e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
            //e.Graphics.TextContrast = 10;
            //e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            //e.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;

            Object.Types type = navigatorObjectTypeTab;
            if (navigatorObjectTypeTab == Object.Types.Inventory) {
                type = Object.Types.Item;
            }

            int countPro = LstFiles.ProTotalCount(type);

            int navPidPosition = 0;
            if (chkLocal.Checked) {
                int pos = navigatorScroll.Value;
                while (pos > 0)
                {
                    if (++navPidPosition >= countPro) break;
                    if (map.editedMap.Objects.ProtoIsLocal(type, navPidPosition)) pos--;
                }
            } else {
                navPidPosition = navigatorScroll.Value;
            }

            int countSlot = panelNavigator.Width / 75;

            for (int i = navPidPosition, n = 0; n < countSlot; i++)
            {
                if (i > countPro) break;
                if (chkLocal.Checked && !map.editedMap.Objects.ProtoIsLocal(type, i)) continue;

                Proto.Proto proto = ProtoFiles.GetProto(type, i);

                int fid = 0;
                switch (navigatorObjectTypeTab)
                {
                    case Object.Types.Inventory:
                        fid = proto.item.InventoryFID;
                        break;
                    default:
                        fid = proto.common.FID;
                        break;
                }

                int dirs = 0;
                if (fid == -1) fid = 0;

                FrmImage frm = FrmFiles.GetFRM(fid);
                if (frm != null)
                {
                    int sW = frm.GetWidth(0, 0);
                    int sH = frm.GetHeight(0, 0);
                    Rectangle sRect = new Rectangle(0, 0, sW, sH);

                    if (sRect.Width > 70 || sRect.Height > 80)
                    { // уменьшаем размер спрайта c соотношением
                        double nW = sRect.Width / 70.0;
                        double nH = sRect.Height / 80.0;

                        double ar = Math.Max(nW, nH);
                        if (ar != 0.0)
                        {
                            sW = (int)(sRect.Width / ar);
                            sH = (int)(sRect.Height / ar);
                        }
                    }
                    // центрируем
                    int y = 40 - (sH / 2);
                    int x = 35 - (sW / 2);

                    Rectangle dRect = new Rectangle(x + 2 + (75 * n), 5 + y, sW, sH);
                    e.Graphics.DrawImage(frm.GetImage(0, 0), dRect, sRect, GraphicsUnit.Pixel);

                    dirs = frm.TotalDirections();

                    if (n == navigatorSelectedSlot) {
                        e.Graphics.DrawRectangle(new Pen(Color.Cyan), dRect);
                    }
                }

                string text = (dirs > 1 && type != Object.Types.Critter) ? String.Format("ID:{0} [{1}]", i, dirs) : String.Format("ID:{0}", i);
                e.Graphics.DrawString(text, panelNavigator.Font, Brushes.White, 10.0f + (n * 75), 80.0f);

                navigatorSlotPids[n++] = i;
            }
        }

        private void panelInventory_Paint(System.Object sender, PaintEventArgs e)
        {
            e.Graphics.Clear(Color.Black);

            Rectangle border = e.ClipRectangle;
            border.Width -= 1;
            border.Height -= 1;
            e.Graphics.DrawRectangle(new Pen(Color.DimGray), border);

            Object.GameObject obj = CurrentInventoryObject(); // последний выбранный объект
            if (obj.inventory.count == 0) {
                e.Graphics.DrawString("Inventory Empty", panelInventory.Font, Brushes.YellowGreen, 30.0f, 5.0f);
                return;
            }

            e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
            e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;

            int countMax = panelInventory.Height / 65;

            inventoryScrollBar.Enabled = (obj.inventory.count > countMax);

            int count = Math.Min(countMax, obj.inventory.count);
            int navN = inventoryScrollBar.Value;

            Rectangle selRect = new Rectangle(5, 8, 120, 60);

            for (int i = 0; i < count; i++)
            {
                if (inventorySelectedIndex == i) {
                    selRect.Y += i * 65;
                    e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(100, Color.Green)), selRect);
                    e.Graphics.DrawRectangle(new Pen(Color.Green), selRect);
                }

                Object.GameObject item = obj.inventory.items[i + navN].item;
                Proto.Proto proto = ProtoFiles.GetProto(item.pid);
                FrmImage frm = FrmFiles.GetFRM(proto.item.InventoryFID);

                int sW = frm.GetWidth(0, 0);
                int sH = frm.GetHeight(0, 0);
                Rectangle sRect = new Rectangle(0, 0, sW, sH);

                if (sRect.Width > 100 || sRect.Height > 50) { // уменьшаем размер спрайта c соотношением размера
                    double nW = sRect.Width / 100.0;
                    double nH = sRect.Height / 50.0;

                    double ar = Math.Max(nW, nH);
                    if (ar != 0.0) {
                        sW = (int)(sRect.Width / ar);
                        sH = (int)(sRect.Height / ar);
                    }
                }
                // центрируем
                int y = 30 - (sH / 2);
                int x = 60 - (sW / 2);

                Rectangle dRect = new Rectangle(5 + x, y + 10 + (i * 65), sW, sH);
                e.Graphics.DrawImage(frm.GetImage(0, 0), dRect, sRect, GraphicsUnit.Pixel);

                if (obj.inventory.items[i + navN].count > 1) e.Graphics.DrawString("x" + obj.inventory.items[i + navN].count.ToString(), panelInventory.Font, Brushes.White, 80.0f, 10.0f + (i * 65));

                switch (obj.inventory.items[i + navN].item.GetSlot())
                {
                    case Object.Slot.Left:
                        e.Graphics.DrawString("Left Hand", panelMinimap.Font, Brushes.YellowGreen, 8.0f, 55.0f + (i * 65));
                        break;
                    case Object.Slot.Right:
                        e.Graphics.DrawString("Right Hand", panelMinimap.Font, Brushes.YellowGreen, 8.0f, 55.0f + (i * 65));
                        break;
                    case Object.Slot.Worn:
                        e.Graphics.DrawString("Armor Slot", panelMinimap.Font, Brushes.YellowGreen, 8.0f, 55.0f + (i * 65));
                        break;
                }

                if (item.inventory.count > 0) {
                    e.Graphics.DrawString("Has Items", panelMinimap.Font, Brushes.White, 75.0f, 10.0f + (i * 65));
                }
            }
        }

        #endregion

        #region Navigator Control
        static private bool skipSavePosition;
        private int lastTipNavigatorN = -1;
        private int selectedInventoryItemPid = -1;

        private int NavigatorScrollSetup() // установка скролла навигатора
        {
            int count = panelNavigator.Width / 75;

            int max = (chkLocal.Checked)
                    ? map.editedMap.Objects.ProtoLocalCount(navigatorObjectTypeTab) + 1 - count
                    : LstFiles.ProTotalCount(navigatorObjectTypeTab) + 1 - count;

            navigatorScroll.Maximum = Math.Max(1, max);
            return count;
        }

        private void navigatorScroll_ValueChanged(System.Object sender, EventArgs e)
        {
            if (skipSavePosition) return;

            navigatorPostion[tabSpritesControl.SelectedIndex] = navigatorScroll.Value;
            panelNavigator.Invalidate();
        }

        private void navigatorScroll_Scroll(System.Object sender, ScrollEventArgs e)
        {
            if (navigatorHasSelect) {
                int delta = e.OldValue - e.NewValue;
                navigatorSelectedSlot += delta;
            }
        }

        // добавление предмета в инвентарь
        private void panelNavigator_MouseDoubleClick(System.Object sender, MouseEventArgs e)
        {
            if (navigatorObjectTypeTab != Object.Types.Inventory || e.Button != MouseButtons.Left) return;

            Object.GameObject obj = CurrentInventoryObject();
            if (obj == null) return;

            if (inventoryStackPos == -1)  {
                if (obj.GetPidType() != Object.Types.Critter)  {
                    if (obj.GetPidType() != Object.Types.Item) return;

                    Proto.Proto proto = ProtoFiles.GetProto(obj.pid);
                    if (proto.item.ItemSubType != Proto.Proto.ItemTypes.Container) return;
                }
            }

            int iCount = obj.inventory.count;

            // добавляем в инвентарь
            map.editedMap.Objects.AddInventoryItem(obj, selectedInventoryItemPid);

            InventorySetup(iCount);
            inventoryScrollBar.Value = inventoryScrollBar.Maximum;

            panelInventory.Invalidate();
        }

        private void panelNavigator_MouseClick(System.Object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left) {
                int n = e.X / 75;
                if (n >= navigatorSlotPids.Length) return;

                navigatorHasSelect = true;
                navigatorSelectedSlot = n;

                Object.Types type = navigatorObjectTypeTab;
                if (type > Object.Types.Misc) type = Object.Types.Item;
                int pid = (int)type << 24 | navigatorSlotPids[navigatorSelectedSlot];

                Proto.Proto proto = ProtoFiles.GetProto(pid);
                tSSLabelName.Text = MsgFiles.GetMsg(navigatorObjectTypeTab, proto.common.MsgID);

                // заливка региона
                if (MapTab.selectedTileRegion > 1) {
                    if (type == Object.Types.Tiles) {
                        if (Main.selectMode == 1)
                            map.editedMap.Tiles.SetFloorRegion(MapTab.startSelectTileX, MapTab.startSelectTileY, MapTab.endSelectTileX, MapTab.endSelectTileY, map.currentLevel, proto.common.FID);
                        else
                            map.editedMap.Tiles.SetRoofRegion(MapTab.startSelectTileX, MapTab.startSelectTileY, MapTab.endSelectTileX, MapTab.endSelectTileY, map.currentLevel, proto.common.FID);

                        RefreshMap();
                    }
                } else {
                    if (navigatorObjectTypeTab == Object.Types.Inventory && panelInventory.Visible) {
                        selectedInventoryItemPid = pid;
                    } else {
                        selectedInventoryItemPid = -1;
                        map.pickObjectPid = pid;
                    }

                    // сбрасываем выделение - если объект не имеет инвентаря
                    if (!panelInventory.Visible || navigatorObjectTypeTab != Object.Types.Inventory) {
                        map.editedMap.Objects.ClearSelectedObject();
                        RefreshMap();
                    }
                }
                panelNavigator.Invalidate();
            }
        }

        private void panelNavigator_MouseMove(System.Object sender, MouseEventArgs e)
        {
            int n = e.X / 75;
            if (navigatorSlotPids[0] == 0 || n >= navigatorSlotPids.Length) return;

            n = navigatorSlotPids[n];

            if (lastTipNavigatorN != n) {
                Object.Types type = navigatorObjectTypeTab;
                if (type > Object.Types.Misc) type = Object.Types.Item;

                Proto.Proto proto = ProtoFiles.GetProto(type, n);

                toolTipNavigation.Active = false;
                toolTipNavigation.SetToolTip(panelNavigator, MsgFiles.GetMsg(type, proto.common.MsgID));
                toolTipNavigation.Active = true;

                lastTipNavigatorN = n;
            }
        }

        private void PanelNavigator_MouseWheel(System.Object sender, MouseEventArgs e)
        {
            int delta = (e.Delta > 0) ? -1 : 1;

            if (delta < 0 && navigatorScroll.Value > 1) {
                if (navigatorHasSelect) navigatorSelectedSlot -= delta;
                navigatorScroll.Value += delta;
            }
            else if (delta > 0 && navigatorScroll.Value < navigatorScroll.Maximum) {
                if (navigatorHasSelect) navigatorSelectedSlot -= delta;
                navigatorScroll.Value += delta;
            }
        }

        private void panelNavigator_MouseEnter(System.Object sender, EventArgs e)
        {
            panelNavigator.Focus();
        }

        private void panelNavigator_MouseLeave(System.Object sender, EventArgs e)
        {
            panelMap.Focus();
        }

        #endregion

        #region Inventory Control
        private int lastTipInventoryN = -1;
        private int panelInventoryMouseDownY;
        private bool skipRedrawInventory = false;

        private static Point[] backPic = { new Point(8, 2), new Point(4, 6), new Point(8, 10) };
        private static SolidBrush penLime = new SolidBrush(Color.Lime);

        //
        private Object.GameObject CurrentInventoryObject()
        {
            return (inventoryStackPos >= 0) ? inventoryObjectStack[inventoryStackPos] : map.editedMap.Objects.GetSelectObject(); // последний выбранный объект;
        }

        private void OpenSubInventory(Object.GameObject obj)
        {
            inventoryObjectStack[++inventoryStackPos] = obj.inventory.items[InventorySelectedItemIndex()].item;

            DeselectInventoryItem();
            panelInventory.Invalidate();

            lastTipInventoryN = -1;
            toolTipCommon.Active = true;
            toolTipInventory.Active = false;
            btnInventoryBack.Visible = true;
        }

        private int InventorySelectedItemIndex()
        {
            return inventorySelectedIndex + inventoryScrollBar.Value;
        }

        private void DeselectInventoryItem()
        {
            inventorySelectedIndex = -1;
            InventoryItemIsSelected = false;
        }

        private void InventoryScrollSetup(int maxCount)
        {
            if (panelInventory.Visible && inventoryScrollBar.Visible) {
                inventoryScrollBar.Value = 0;
                if (maxCount == 0) {
                    Object.GameObject obj = CurrentInventoryObject();
                    maxCount = obj.inventory.count;
                }
                int count = panelInventory.Height / 65;
                inventoryScrollBar.Maximum = Math.Max(0, maxCount - count);
            }
        }

        private void InventorySetup(int maxCount)
        {
            if (maxCount == 0) {
                int h = panelMap.Height - panelInventory.Location.Y;
                h -= (h % 65);
                panelInventory.Height = h + 8;
                panelInventory.Anchor |= AnchorStyles.Bottom;

                inventoryScrollBar.Value = 0;
                inventoryScrollBar.Visible = true;
            }
            maxCount++;

            int count = panelInventory.Height / 65;
            inventoryScrollBar.Maximum = Math.Max(0, maxCount - count);
        }

        private void panelInventory_MouseClick(System.Object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left && e.Y > 5 && e.X <= 125) {
                Object.GameObject obj = CurrentInventoryObject();
                if (obj.inventory.count > 0) {
                    int selectedIndex = (e.Y - 10) / 65;
                    inventorySelectedIndex = (selectedIndex < obj.inventory.count) ? selectedIndex : -1;
                    InventoryItemIsSelected = inventorySelectedIndex != -1;

                    panelInventory.Invalidate();
                } else {
                    DeselectInventoryItem();
                }
            }
        }

        private void panelInventory_MouseDoubleClick(System.Object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left && InventoryItemIsSelected) {
                Object.GameObject obj = CurrentInventoryObject();
                Object.GameObject item = obj.inventory.items[InventorySelectedItemIndex()].item;

                Proto.Proto proto = ProtoFiles.GetProto(item.pid);

                if (proto.item.ItemSubType == Proto.Proto.ItemTypes.Container) {
                    OpenSubInventory(obj);
                }
            }
        }

        private void panelInventory_MouseMove(System.Object sender, MouseEventArgs e)
        {
            Object.GameObject obj = CurrentInventoryObject();
            if (obj.inventory.count > 0) {
                int selectedIndex = (e.Y - 10) / 65;
                if (lastTipInventoryN == selectedIndex) return;

                if (selectedIndex < obj.inventory.count) {
                    selectedIndex += inventoryScrollBar.Value;
                    int pid = obj.inventory.items[selectedIndex].item.pid;
                    Proto.Proto proto = ProtoFiles.GetProto(pid);

                    toolTipCommon.Active = false;

                    toolTipInventory.Active = false;
                    toolTipInventory.SetToolTip(panelInventory, MsgFiles.GetMsg(Object.Types.Item, proto.common.MsgID));
                    toolTipInventory.Active = true;
                } else {
                    toolTipCommon.Active = true;
                    toolTipInventory.Active = false;
                }
                lastTipInventoryN = selectedIndex;
            } else {

            }
        }

        private void panelInventory_MouseEnter(System.Object sender, EventArgs e)
        {
            panelInventory.Focus();
        }

        private void panelInventory_MouseLeave(System.Object sender, EventArgs e)
        {
            panelMap.Focus();
        }

        private void panelInventory_MouseDown(System.Object sender, MouseEventArgs e)
        {
            panelInventoryMouseDownY = e.Y;
        }

        private void PanelInventory_MouseWheel(System.Object sender, MouseEventArgs e)
        {
            int delta = (e.Delta > 0) ? -1 : 1;

            if (delta < 0 && inventoryScrollBar.Value > 0) {
                if (InventoryItemIsSelected) inventorySelectedIndex -= delta;
                inventoryScrollBar.Value += delta;
            }
            else if (delta > 0 && inventoryScrollBar.Value < inventoryScrollBar.Maximum) {
                if (InventoryItemIsSelected) inventorySelectedIndex -= delta;
                inventoryScrollBar.Value += delta;
            }
        }

        private void inventoryScrollBar_ValueChanged(System.Object sender, EventArgs e)
        {
            if (!skipRedrawInventory) {
                panelInventory.Invalidate();
            }
        }

        private void inventoryScrollBar_Scroll(System.Object sender, ScrollEventArgs e)
        {
            if (!InventoryItemIsSelected)
                return;

            int delta = e.OldValue - e.NewValue;
            inventorySelectedIndex += delta;
        }

        private void btnInventoryBack_Paint(System.Object sender, PaintEventArgs e)
        {
            e.Graphics.FillPolygon(penLime, backPic);
        }

        private void panelInventory_VisibleChanged(System.Object sender, EventArgs e)
        {
            if (panelInventory.Visible == false) btnInventoryBack.Visible = false;
        }

        #endregion

        #region Map Control
        private bool skipOpenContextMapMenu;

        private void panelMap_MouseUp(System.Object sender, MouseEventArgs e)
        {
            scrollMapMode = false;

            if (map.selectedObjectMode && e.Button == MouseButtons.Left) {
                inventoryStackPos = -1;
                map.selectedObjectMode = false;

                // выбираем объект
                if (MapTab.startSelectMouseX == e.X || MapTab.startSelectMouseY == e.Y) {
                    if (!SelectObjectXY(e.X, e.Y)) map.editedMap.Objects.ClearSelectedObject();

                    RotationControl();
                }
                RefreshMap();

                if (map.editedMap.Objects.SelectedCount() == 1) {
                    Object.GameObject obj = map.editedMap.Objects.GetSelectObject(); // последний выбранный объект

                    skipRedrawInventory = true;

                    Proto.Proto proto = ProtoFiles.GetProto(obj.pid);
                    tSSLabelName.Text = MsgFiles.GetMsg(obj.GetPidType(), proto.common.MsgID);

                    Object.Types type = obj.GetPidType();
                    if (type == Object.Types.Item) {
                        if (proto.item.ItemSubType == Proto.Proto.ItemTypes.Container) {
                            type = Object.Types.Critter;
                        }
                    }
                    panelInventory.Visible = (type == Object.Types.Critter);

                    if (panelInventory.Visible) {
                        if (lastTipInventoryN != -1) {
                            lastTipInventoryN = -1;
                            toolTipCommon.Active = true;
                            toolTipInventory.Active = false;
                        }

                        inventoryScrollBar.Value = 0;
                        panelInventory.Top = 5 + panelMinimap.Bottom;

                        if (obj.inventory.count == 0) {
                            panelInventory.Height = 25;
                            panelInventory.Anchor ^= AnchorStyles.Bottom;
                            inventoryScrollBar.Visible = false;
                        } else {
                            int h = panelMap.Height - panelInventory.Location.Y;
                            h -= (h % 65);
                            panelInventory.Height = h + 8;
                            panelInventory.Anchor |= AnchorStyles.Bottom;
                            inventoryScrollBar.Visible = true;

                            InventoryScrollSetup(obj.inventory.count);
                        }
                        panelInventory.Invalidate();
                    }
                    skipRedrawInventory = false;
                    inventorySelectedIndex = -1;
                    InventoryItemIsSelected = false;
                } else {
                    panelInventory.Visible = false;
                    tSSLabelName.Text = string.Empty;
                }
            } else if (Main.selectMode != 0 && e.Button == MouseButtons.Left) {
                MapTab.selectedTileRegion = 2;
            }

        }

        private void panelMap_MouseDown(System.Object sender, MouseEventArgs e)
        {
            if (!scrollMapMode && e.Button == MouseButtons.Middle) {
                scrollMapMode = true;
                scrollDownMouseX = e.X;
                scrollDownMouseY = e.Y;

                Cursor.Current = Cursors.NoMove2D;
            } else if (e.Button == MouseButtons.Right) {
                MapTab.selectedTileRegion = 0; // сбросить выделение

                if (map.pickObjectPid != -1) {
                    skipOpenContextMapMenu = true;

                    map.pickObjectPid = -1;
                    navigatorSelectedSlot = -1;
                    navigatorHasSelect = false;
                    panelNavigator.Invalidate();
                }
                RefreshMap();
            }
            else if (Main.selectMode == 0 && map.pickObjectPid == -1 && e.Button == MouseButtons.Left) {
                MapTab.startSelectMouseX = e.X;
                MapTab.startSelectMouseY = e.Y;
                map.selectedObjectMode = !map.moveObjectMode;

                Utilites.GetCursorHex(e.X, e.Y, map.cWorldX, map.cWorldY, out downHexX, out downHexY);
            }
            else if (Main.selectMode != 0 && e.Button == MouseButtons.Left) {
                Utilites.GetCursorTile(e.X, e.Y, map.cWorldX, map.cWorldY, out downTileX, out downTileY);
                if (MapTab.selectedTileRegion == 0) {
                    MapTab.startSelectTileX = downTileX;
                    MapTab.startSelectTileY = downTileY;
                    MapTab.selectedTileRegion = 1;
                }
            }
        }

        private void panelMap_MouseMove(System.Object sender, MouseEventArgs e)
        {
            MapTab.mouseX = e.X;
            MapTab.mouseY = e.Y;

            if (scrollMapMode) {
                map.selectedObjectMode = false;

                int deltaX = e.X - scrollDownMouseX;
                int deltaY = e.Y - scrollDownMouseY;

                map.cWorldX -= deltaX;
                map.cWorldY -= deltaY;

                if (map.cWorldX < -2000 || map.cWorldX > 8000) map.cWorldX += deltaX;
                if (map.cWorldY < -1000 || map.cWorldY > 4000) map.cWorldY += deltaY;

                RefreshMap();

                if (!minimapHide) {
                    panelMinimap.Invalidate(false);
                    panelMinimap.Update();
                }

                scrollDownMouseX = e.X;
                scrollDownMouseY = e.Y;
                return;
            }

            int tileX, tileY;
            Utilites.GetCursorTile(e.X, e.Y, map.cWorldX, map.cWorldY, out tileX, out tileY);
            toolLabelTile.Text = string.Format(toolLabelTile.Tag.ToString(), tileX, tileY);

            int hexX, hexY;
            Utilites.GetCursorHex(e.X, e.Y, map.cWorldX, map.cWorldY, out hexX, out hexY);
            toolLabelHEX.Text = string.Format(toolLabelHEX.Tag.ToString(), Utilites.GetHex(hexX, hexY), hexX, hexY);

            if (MapTab.selectedTileRegion == 2 && e.Button == MouseButtons.Left) {
                MapTab.startSelectTileX = downTileX;
                MapTab.startSelectTileY = downTileY;
                MapTab.selectedTileRegion = 1;
            }
            if (MapTab.selectedTileRegion == 1) {
                MapTab.endSelectTileX = tileX;
                MapTab.endSelectTileY = tileY;
            }

            if (map.selectedObjectMode || MapTab.selectedTileRegion == 1) {
                if (Main.selectMode == 0) {
                    SelectObjRegion(Math.Min(MapTab.startSelectMouseX, e.X), Math.Min(MapTab.startSelectMouseY, e.Y),
                                    Math.Max(e.X, MapTab.startSelectMouseX), Math.Max(e.Y, MapTab.startSelectMouseY));

                    RotationControl();
                }
                RefreshMap();
            }
            else if (map.moveObjectMode) {
                if (e.Button == MouseButtons.Left && map.editedMap.Objects.ObjectsIsSelected()) {
                    if (hexX < 0) hexX = 0; else if (hexX >= 200) hexX = 199;
                    if (hexY < 0) hexY = 0; else if (hexY >= 200) hexY = 199;

                    int deltaX = hexX - downHexX;
                    int deltaY = hexY - downHexY;
                    if (deltaX != 0 || deltaY != 0) {

                        map.editedMap.Objects.MoveSelectedObjects(deltaX, deltaY);

                        downHexX = hexX;
                        downHexY = hexY;

                        RefreshMap();
                        map.MapChangeState(true);
                    }
                }
            } else {
                if (map.pickObjectPid != -1 && map.mouseOverMap) {
                    int  mapX, mapY;
                    bool drawTile = (Object.Types)(map.pickObjectPid >> 24) == Object.Types.Tiles;

                    if (drawTile) {
                        Utilites.GetTileWorldCoord(tileX, tileY, out mapX, out mapY);
                    } else  {
                        Utilites.GetHexWorldCoord(hexX, hexY, out mapX, out mapY);
                    }

                    if (mapX != map.placementObjX || mapY != map.placementObjY) {
                        map.placementObjX = mapX;
                        map.placementObjY = mapY;

                        if (drawTile) RefreshMapTile(tileX, tileY); else RefreshMap();
                    }
                }
            }
        }

        private void panelMap_MouseClick(System.Object sender, MouseEventArgs e)
        {
            // Размещение выбранного объекта на карте
            if (e.Button == MouseButtons.Left && map.pickObjectPid != -1) {
                if ((Object.Types)(map.pickObjectPid >> 24) == Object.Types.Tiles) { // Рисование тайлов
                    if (MapTab.selectedTileRegion > 1) {


                    }

                    int tileX, tileY;
                    Utilites.GetCursorTile(e.X, e.Y, map.cWorldX, map.cWorldY, out tileX, out tileY);
                    if (tileX < 0 || tileX > 100 || tileY < 0 || tileY > 100) return;

                    Proto.Proto proto = ProtoFiles.GetProto(map.pickObjectPid);

                    if (map.ShowObjects(Main.ShowTypes.RoofTiles)) {
                        map.editedMap.Tiles.SetRoofID(tileX, tileY, map.currentLevel, proto.common.FID);
                    } else {
                        map.editedMap.Tiles.SetFloorID(tileX, tileY, map.currentLevel, proto.common.FID);
                    }
                } else {
                    int hexX, hexY;
                    Utilites.GetCursorHex(e.X, e.Y, map.cWorldX, map.cWorldY, out hexX, out hexY);
                    if (hexX < 0 || hexX >= 200 || hexY < 0 || hexY >= 200) return;

                    map.selectedObjectMode = false;

                    int rotation = (!chkRndRotation.Checked) ? (int)numObjectRotation.Value : -1;
                    Object.GameObject placeObj = map.editedMap.Objects.PlacementObject(map.pickObjectPid, Utilites.GetHex(hexX, hexY), rotation, (map.currentLevel - 1));

                    if (chkAutoSelect.Checked) map.editedMap.Objects.SelectObject(placeObj);

                    PrintTotalObjects();
                }
                RefreshMap();
                //map.selectedObjectMode = true;

                map.MapChangeState(true);
            }
        }

        private void panelMap_MouseEnter(System.Object sender, EventArgs e)
        {
            map.mouseOverMap = true;
        }

        private void panelMap_MouseLeave(System.Object sender, EventArgs e)
        {
            map.mouseOverMap = false;
        }

        #endregion

        #region Minimap Control
        private bool minimapMouseDown;

        private void UpdateMiniMap()
        {
            MapDraw.DrawMinimap(map); // рисуем миникарту
            panelMinimap.Invalidate();
        }

        private bool MinimapLocatorMove(MouseEventArgs e)
        {
            if (e.X < 25 || e.X > 125 || e.Y < 35 || e.Y > 135) return false;

            int x = e.X - 25 + 2;
            int y = e.Y - 35 - 4;

            Utilites.GetWorldCoord(x, y, MapTab.cMapViewPortW, MapTab.cMapViewPortH, ref map.cWorldX, ref map.cWorldY);
            RefreshMap();
            return true;
        }

        private void panelMinimap_MouseUp(System.Object sender, MouseEventArgs e)
        {
            minimapMouseDown = false;
        }

        private void panelMinimap_MouseDown(System.Object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left) {
                minimapMouseDown = true;
                if (MinimapLocatorMove(e)) panelMinimap.Invalidate();
            }
        }

        private void panelMinimap_MouseMove(System.Object sender, MouseEventArgs e)
        {
            if (minimapMouseDown && MinimapLocatorMove(e)) {
                panelMinimap.Invalidate(false);
                panelMinimap.Update();
            }
        }

        private void btnUpdateMinimap_Click(System.Object sender, EventArgs e)
        {
            UpdateMiniMap();
        }

        private void btnMinimapHide_MouseClick(System.Object sender, MouseEventArgs e)
        {
            minimapHide = !minimapHide;
            panelMinimap.Height = (minimapHide) ? 25 : 150;

            if (!minimapHide) UpdateMiniMap();

            Object.GameObject obj = map.editedMap.Objects.GetSelectObject();
            if (obj != null) {

                int y = panelInventory.Top;
                panelInventory.Top = 5 + panelMinimap.Bottom;

                if (obj.inventory.count > 0) {
                    panelInventory.Height += (y - panelInventory.Top);
                }
                if (panelInventory.Visible) panelInventory.Invalidate();
            }
        }

        private void numericUpDownElevation_ValueChanged(System.Object sender, EventArgs e)
        {
            map.currentLevel = (int)numericElevation.Value;
            RefreshMap();

            if (!minimapHide) UpdateMiniMap();
        }

        private void numericUpDown2_MouseDown(System.Object sender, MouseEventArgs e)
        {
            panelMinimap.Focus();
        }

        #endregion

        private void SelectObjRegion(int x, int y, int x2, int y2)
        {
            bool altDown = KeyInput.Keyboard.IsKeyDown(KeyInput.Key.LeftAlt);
            bool ctrlDown = KeyInput.Keyboard.IsKeyDown(KeyInput.Key.LeftCtrl);

            for (int i = map.editedMap.Objects.List(map.currentLevel).Count - 1; i >= 0; i--)
            {
                Object.GameObject obj = map.editedMap.Objects.List(map.currentLevel)[i];
                if (obj.tile == -1) continue;

                // пропускаем скрытые объекты
                if (!map.ShowObjects((Main.ShowTypes)obj.GetFidType())) {
                    if (obj.selected) map.editedMap.Objects.RemoveSelectObject(obj);
                    continue;
                }
                FrmImage frm = FrmFiles.GetFRM(obj.fid);

                int w = frm.GetWidth(obj.rotation, obj.frame);
                int h = frm.GetHeight(obj.rotation, obj.frame);

                int tileX, tileY, mapX, mapY;
                obj.GetHexXY(out tileX, out tileY);
                Utilites.GetHexWorldCoord(tileX, tileY, out mapX, out mapY);

                int xObj = mapX - map.cWorldX - (w >> 1) + frm.GetXOffDir(obj.rotation) + obj.x;
                int yObj = mapY - map.cWorldY - h + frm.GetYOffDir(obj.rotation) + obj.y;

                if ((xObj + w) > x && xObj < x2 && ((yObj + h) > y && yObj < y2)) {
                    if (altDown) {
                        if (obj.selected) map.editedMap.Objects.RemoveSelectObject(obj);
                    } else {
                        if (!obj.selected) map.editedMap.Objects.AddSelectObject(obj);
                    }
                } else {
                    if (obj.selected && (!ctrlDown && !altDown)) map.editedMap.Objects.RemoveSelectObject(obj);
                }
            }
        }

        private bool SelectObjectXY(int x, int y)
        {
            bool altDown = KeyInput.Keyboard.IsKeyDown(KeyInput.Key.LeftAlt);
            bool ctrlDown = KeyInput.Keyboard.IsKeyDown(KeyInput.Key.LeftCtrl);

            for (int i = map.editedMap.Objects.List(map.currentLevel).Count - 1; i >= 0; i--)
            {
                Object.GameObject obj = map.editedMap.Objects.List(map.currentLevel)[i];
                if (obj.tile == -1) continue;

                // пропускаем скрытые объекты
                if (!map.ShowObjects((Main.ShowTypes)obj.GetFidType())) {
                    if (obj.selected) map.editedMap.Objects.RemoveSelectObject(obj);
                    continue;
                }

                FrmImage frm = FrmFiles.GetFRM(obj.fid);

                int w = frm.GetWidth(obj.rotation, obj.frame);
                int h = frm.GetHeight(obj.rotation, obj.frame);

                int tileX, tileY, mapX, mapY;
                obj.GetHexXY(out tileX, out tileY);
                Utilites.GetHexWorldCoord(tileX, tileY, out mapX, out mapY);

                int xObj = mapX - map.cWorldX - (w >> 1) + frm.GetXOffDir(obj.rotation) + obj.x;

                if (x < xObj || x >= (xObj + w)) continue;

                int yObj = mapY - map.cWorldY - h + frm.GetYOffDir(obj.rotation) + obj.y;

                if (y < yObj || y >= (yObj + h)) continue;

                if (frm.GetPixel(x - xObj, y - yObj, obj.rotation, obj.frame) != 0) {
                    if (ctrlDown) {
                        if (!obj.selected) map.editedMap.Objects.AddSelectObject(obj);
                    }
                    else if (altDown) {
                        map.editedMap.Objects.RemoveSelectObject(obj);
                    }
                    else {
                        map.editedMap.Objects.SelectObject(obj);
                    }
                    return true;
                }
            }
            return (ctrlDown || altDown);
        }

        private bool skipRotationChange;

        private void RotationControl()
        {
            skipRotationChange = true;

            if (map.editedMap.Objects.SelectedCount() == 1) {
                Object.GameObject obj = map.editedMap.Objects.GetSelectObject();
                numObjectRotation.Value = obj.rotation;

                if (obj.GetFidType() != Object.Types.Critter) {
                    FrmImage frm = FrmFiles.GetFRM(obj.fid);
                    numObjectRotation.Enabled = (frm.TotalDirections() > 1);
                    skipRotationChange = false;
                    return;
                }
                numObjectRotation.Enabled = true;
            } else {
                numObjectRotation.Value = 0;
                numObjectRotation.Enabled = false;
            }

            skipRotationChange = false;
        }

        private void numericRotation_ValueChanged(System.Object sender, EventArgs e)
        {
            if (skipRotationChange) return;

            if (numObjectRotation.Value > 5) numObjectRotation.Value = 0;
            if (numObjectRotation.Value < 0) numObjectRotation.Value = 5;

            var obj = map.editedMap.Objects.GetSelectObject();
            if (obj != null && obj.rotation != numObjectRotation.Value) {
                obj.rotation = (int)numObjectRotation.Value;
                RefreshMap();

                map.MapChangeState(true);
            }
        }

        private void tabSpratesControl_Selected(System.Object sender, TabControlEventArgs e)
        {
            switch (e.TabPageIndex)
            {
                case 0:
                    navigatorObjectTypeTab = Object.Types.Tiles;
                    break;
                case 1:
                    navigatorObjectTypeTab = Object.Types.Walls;
                    break;
                case 2:
                    navigatorObjectTypeTab = Object.Types.Scenery;
                    break;
                case 3:
                    navigatorObjectTypeTab = Object.Types.Critter;
                    break;
                case 4:
                    navigatorObjectTypeTab = Object.Types.Item;
                    break;
                case 5:
                    navigatorObjectTypeTab = Object.Types.Misc;
                    break;
                case 6:
                    navigatorObjectTypeTab = Object.Types.Inventory;
                    break;
            }

            skipSavePosition = true;

            NavigatorScrollSetup();
            navigatorScroll.Value = navigatorPostion[e.TabPageIndex];
            navigatorSelectedSlot = -1;
            navigatorHasSelect = false;
            skipSavePosition = false;

            panelNavigator.Invalidate();
        }

        private void contextMenuInventory_Opening(System.Object sender, CancelEventArgs e)
        {
            if (!InventoryItemIsSelected) {
                tsmDeleteItem.Enabled = false;
                toolStripMenuItem4.Enabled = false;
                toolStripComboBox1.Enabled = false;
                tsmItemSubInventory.Enabled = false;
            } else {
                tsmDeleteItem.Enabled = true;
                toolStripMenuItem4.Enabled = true;
                toolStripComboBox1.Enabled = true;

                if (inventoryStackPos < 9) {
                    Object.GameObject obj = CurrentInventoryObject();
                    Object.GameObject item = obj.inventory.items[InventorySelectedItemIndex()].item;

                    Proto.Proto proto = ProtoFiles.GetProto(item.pid);
                    tsmItemSubInventory.Enabled = (proto.item.ItemSubType == Proto.Proto.ItemTypes.Container);
                } else {
                    tsmItemSubInventory.Enabled = false;
                }
            }
            tsmBackParent.Enabled = (inventoryStackPos >= 0);
        }

        private void contextMenuInventory_Opened(System.Object sender, EventArgs e)
        {
            if (Cursor.Position.X < Screen.PrimaryScreen.Bounds.Width - 100) return;

            contextMenuInventory.Show(panelInventory, 0, panelInventoryMouseDownY);
        }

        private void toolStripMenuItem4_Click(System.Object sender, EventArgs e)
        {
            Object.GameObject obj = map.editedMap.Objects.GetSelectObject();
            int itemIndex = inventorySelectedIndex + inventoryScrollBar.Value;

            ItemCount count = new ItemCount(obj.inventory.items[itemIndex].count);
            if (count.ShowDialog() == DialogResult.OK) {
                obj.inventory.items[itemIndex].count = ((int)count.numericCounts.Value);
                panelInventory.Invalidate();

                map.MapChangeState(true);
            }
        }

        private void tsMenuAddItem_Click(System.Object sender, EventArgs e)
        {
            tabSpritesControl.SelectTab((int)Object.Types.Inventory - 1);
        }

        private void tsmDeleteItem_Click(System.Object sender, EventArgs e)
        {
            if (MessageBox.Show("Действительно удалить предмет из инвентаря?", Application.ProductName, MessageBoxButtons.YesNo) == DialogResult.No) return;

            Object.GameObject obj = map.editedMap.Objects.GetSelectObject();
            int itemIndex = inventorySelectedIndex + inventoryScrollBar.Value;
            map.editedMap.Objects.RemoveInventoryItem(obj, itemIndex);

            DeselectInventoryItem();

            if (inventoryScrollBar.Maximum > 0) {
                inventoryScrollBar.Maximum--;
            }
            panelInventory.Invalidate();

            map.MapChangeState(true);
        }

        private void tsmItemSubInventory_Click(System.Object sender, EventArgs e)
        {
            OpenSubInventory(CurrentInventoryObject());
        }

        private void tsmBackParent_Click(System.Object sender, EventArgs e)
        {
            inventoryStackPos--;
            btnInventoryBack.Visible = (inventoryStackPos >= 0);
            panelInventory.Invalidate();
        }

        private void chkLocal_MouseClick(System.Object sender, MouseEventArgs e)
        {
            navigatorPostion[0] = 1;
            navigatorPostion[1] = 1;
            navigatorPostion[2] = 1;
            navigatorPostion[3] = 1;
            navigatorPostion[4] = 1;
            navigatorPostion[5] = 1;
            navigatorPostion[6] = 1;

            skipSavePosition = true;

            navigatorScroll.Value = 1;
            NavigatorScrollSetup();
            navigatorSelectedSlot = -1;
            navigatorHasSelect = false;

            skipSavePosition = false;

            panelNavigator.Invalidate();
        }

        private void contextMenuMap_Opening(System.Object sender, CancelEventArgs e)
        {
            if (skipOpenContextMapMenu || Main.selectMode != 0) {
                skipOpenContextMapMenu = false;
                e.Cancel = true;
                return;
            }
        }
    }
}
